#!/usr/bin/python
# -*- coding: utf-8 -*-# @version        : 1.0
# @Create Time    : 2025/8/23
# @File           : log_config.py
# @IDE            : PyCharm
# @Desc           : 日志配置参数管理

# 日志配置参数管理
import os
import sys
from dataclasses import dataclass, field
from typing import Dict, List, Any

from applications import settings


@dataclass
class LogConfig:
    """日志配置类"""
    log_path: str = settings.LOG_PATH
    debug: bool = settings.DEBUG
    retention: str = "30 days"
    rotation: str = "100 MB"
    enqueue: bool = True
    encoding: str = "utf-8"
    compression: str = "zip"
    backtrace: bool = settings.DEBUG
    diagnose: bool = settings.DEBUG
    handlers: List[Dict[str, Any]] = field(default_factory=list)

    def __post_init__(self):
        # 确保日志目录存在
        os.makedirs(self.log_path, exist_ok=True)
        for sub in ("err", "info", "debug"):
            os.makedirs(os.path.join(self.log_path, sub), exist_ok=True)
        self._init_handlers()

    @staticmethod
    def _only_level(level_name: str):
        # 分级不重叠
        return lambda record: record["level"].name == level_name

    @staticmethod
    def _levels(level_names: set):
        return lambda record: record["level"].name in level_names

    def _init_handlers(self):
        """初始化日志处理器"""
        err_log_file_path = os.path.join(self.log_path, "err", "err_{time:YYYY-MM-DD}.log")
        info_log_file_path = os.path.join(self.log_path, "info", "info_{time:YYYY-MM-DD}.log")
        debug_log_file_path = os.path.join(self.log_path, "debug", "debug_{time:YYYY-MM-DD}.log")

        common_settings = {
            "enqueue": self.enqueue,
            "encoding": self.encoding,
            "compression": self.compression,
            "retention": self.retention,
            "rotation": self.rotation,
            "backtrace": self.backtrace,
            "diagnose": self.diagnose,
        }

        text_format = (
            "<level>[{level}]</level> | <green>{time:YYYY-MM-DD HH:mm:ss}</green> -> "
            "<magenta>{extra[trace_id]}</magenta> | <cyan>{module}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> - {message}"
        )
        err_format = (
            "<red>[{level}]</red> | <green>{time:YYYY-MM-DD HH:mm:ss}</green> -> "
            "<magenta>{extra[trace_id]}</magenta> | <cyan>{module}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> - {message}"
        )
        dbg_format = (
            "<cyan>[{level}]</cyan> | <green>{time:YYYY-MM-DD HH:mm:ss}</green> -> "
            "<magenta>{extra[trace_id]}</magenta> | <cyan>{module}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> - {message}"
        )

        # 信息日志（仅 INFO）
        self.handlers.append({
            "sink": info_log_file_path,
            "level": "INFO",
            "filter": self._only_level("INFO"),
            "format": text_format,
            "serialize": False,
            **common_settings,
        })

        # 错误日志（ERROR + CRITICAL）
        self.handlers.append({
            "sink": err_log_file_path,
            "level": "ERROR",
            "filter": self._levels({"ERROR", "CRITICAL"}),
            "format": err_format,
            "serialize": False,
            **common_settings,
        })

        # 调试日志（仅在 debug 模式）
        if self.debug:
            self.handlers.append({
                "sink": debug_log_file_path,
                "level": "DEBUG",
                "filter": self._only_level("DEBUG"),
                "format": dbg_format,
                "serialize": False,
                **common_settings,
            })

            # 控制台输出
            self.handlers.append({
                "sink": sys.stdout,
                "level": "DEBUG",
                "format": text_format,
                "colorize": True,
                "serialize": False,
            })
        else:
            # 非 debug 环境也输出控制台，但从 INFO 开始
            self.handlers.append({
                "sink": sys.stdout,
                "level": "INFO",
                "format": text_format,
                "colorize": True,
                "serialize": False,
            })


# 导出配置实例
log_config = LogConfig()